
package org.crepi22.finecrop;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.util.Stack;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.event.MouseInputListener;

/**
 * @author pierre A window to display an image to rotate and clip.
 */
/**
 * @author pierre
 *
 */
public class PhotoView extends JComponent implements MouseInputListener  {

    private static final long serialVersionUID = 1L;


    private Continuation continuation;
    private Photo photo;
    private int startY;
    private int startX;
    private int endY;
    private int x;
    private int y;
    private int endX;
    private int mode;
    private float ratio;
    private Stack<Rectangle> rectangles = new Stack<Rectangle>();

    /**
     * Constructor of the panel.
     * 
     * @throws IOException
     */
    public PhotoView(JFrame frame) throws IOException {
        addMouseListener(this);
        addMouseMotionListener(this);
    }


    /**
     * Register a photo for treatment. The second argument is the continuation
     * executed when we have finished.
     * 
     * @param file File containing the photo.
     * @param mode transformation to perform
     */
    public void setPhoto(File file, int mode) {
        this.mode = mode;
        rectangles.clear();
        startX = -1;
        endX = -1;
        startY = -1;
        endY = -1;
        try {
            photo = new Photo(file);
        } catch (IOException e) {
            continuation.error(e.getMessage());
        }
        repaint();
    }

 
    /**
     * Continuation: what to do next.
     * @param continuation
     */
    public void setContinuation(Continuation continuation) {
        this.continuation = continuation;
    }
    
    private void performAction() {
        switch (mode) {
            case FCAction.ROTATE:
                if (startX > 0 & endX > 0) {
                    new Rotate(continuation, photo, startX, startY, endX, endY).start();
                } else {
                    continuation.runFile(photo.getFile());
                }
                break;
            case FCAction.CROP:
                if (startX > 0 && endX > 0) {
                    new Clip(continuation, photo, (startX - x) / ratio, (startY - y) / ratio,
                            (endX - x) / ratio, (endY - y) / ratio).start();
                } else {
                    continuation.runFile(photo.getFile());
                }
                break;
            case FCAction.MULTICROP:
                if (rectangles.size() > 0) {
                    new MultiCrop(continuation, photo, rectangles, x, y, ratio).start();
                } else {
                    continuation.runFile(photo.getFile());
                }
                break;
            case FCAction.CONFIRM:
                continuation.runFile(photo.getFile());
                break;
            default:
        }
    }

    private void cancelAction() {
        switch(mode) {
            case FCAction.MULTICROP:
                if (rectangles.isEmpty()) continuation.cancel();
                else {
                    rectangles.pop();
                    repaint();
                }
                break;
            case FCAction.CROP:
            case FCAction.ROTATE:
                if (startX >= 0 && endX >= 0) {
                    startX = -1;
                    endX = -1;
                    repaint();
                } else continuation.cancel();
                break;
            default:
                continuation.cancel();
        }        
    }

    // MOUSE BINDINGS

    @Override
    public void mousePressed(MouseEvent evt) {
        switch (evt.getButton()) {
            case MouseEvent.BUTTON1:
                startX = evt.getX();
                startY = evt.getY();
                break;
            case MouseEvent.BUTTON2:
                performAction();
                break;
            case MouseEvent.BUTTON3:
                cancelAction();
        }

    }

    @Override
    public void mouseReleased(MouseEvent evt) {

            switch(evt.getButton()) {
                case MouseEvent.BUTTON1:
                    endX = evt.getX();
                    endY = evt.getY();
                    if(mode == FCAction.MULTICROP) {
                        Rectangle r = new Rectangle(startX, startY, endX - startX, endY - startY);
                        rectangles.push(r);
                        startX = -1;
                        startY = -1;
                        endX = -1;
                        endY = -1;
                    }
                    repaint();
            }

    }

    @Override
    public void mouseClicked(MouseEvent arg0) {
    }

    @Override
    public void mouseEntered(MouseEvent arg0) {
        if(!hasFocus()) { requestFocus(); }
    }

    @Override
    public void mouseExited(MouseEvent arg0) {
    }

    @Override
    public void mouseMoved(MouseEvent arg0) {
    }

    @Override
    public void mouseDragged(MouseEvent evt) {
        if(startX > 0) {
                endX = evt.getX();
                endY = evt.getY();
                repaint();
        }
    }

    // COMPONENT PAINTING
    
    @Override
    public void paintComponent(Graphics g) {
        int w = getWidth();
        int h = getHeight();
        g.setColor(Color.BLACK);
        int wP = photo.photoWidth;
        int hP = photo.photoHeight;
        g.fillRect(0, 0, w, h);
        if (photo != null) {
            float rw = (float) w / wP;
            float rh = (float) h / hP;
            ratio = Math.min(rw, rh);
            int wp = (int) (wP * ratio);
            int hp = (int) (hP * ratio);
            x = (w - wp) / 2;
            y = (h - hp) / 2;
            g.drawImage(photo.getImage(), x, y, wp, hp, null);
        }
        g.setColor(Color.BLACK);
        for(Rectangle r: rectangles) {
            g.drawRect(r.x,r.y, r.width, r.height);
        }
        switch (mode) {
            case FCAction.ROTATE:
                if (startX >= 0 && endX > 0) {
                    g.drawLine(startX, startY, endX, endY);
                }
                break;
            case FCAction.CROP:
            case FCAction.MULTICROP:
                if (startX >= 0 && endX > 0) {
                    g.drawRect(startX, startY, endX - startX, endY - startY);
                }
                break;
        }
    }


}
